package br.com.intelsys.basics.spring;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.View;

import br.com.intelsys.basics.utils.TextCleaner;

public abstract class FileAbstractView implements View {
	private static final String NO_CACHE = "no-cache, must-revalidate";
	private static final String CACHE_CONTROL = "Cache-Control";
	private static final String ATTACHMENT_FILENAME = "attachment; filename=";
	private static final String CONTENT_DISPOSITION = "Content-Disposition";
	private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
	private final boolean attached;
	private String filePath;
	private String contentType;
	private String fileNameDisplayed;
	private InputStream inputStream;
	private static MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();

	public FileAbstractView(String filePath, boolean attached) {
		this(filePath, attached, null);
	}

	public FileAbstractView(String filePath, boolean attached, String fileNameDisplayed) {
		this.filePath = filePath;
		this.attached = attached;
		TextCleaner tc = new TextCleaner(fileNameDisplayed);
		tc.keepUrlParam();
		this.fileNameDisplayed = tc.toString();
	}

	public FileAbstractView(InputStream inputStream, boolean attached) {
		this(inputStream, attached, null);
	}

	public FileAbstractView(InputStream inputStream, boolean attached, String fileNameDisplayed) {
		this.inputStream = inputStream;
		this.attached = attached;
		this.fileNameDisplayed = fileNameDisplayed;
	}

	public FileAbstractView(File file, boolean attached) {
		this(file, attached, null);
	}

	public FileAbstractView(File file, boolean attached, String fileNameDisplayed) {
		this.filePath = file.getAbsolutePath();
		this.attached = attached;
		this.fileNameDisplayed = fileNameDisplayed;
	}

	public String getContentType() {
		return contentType;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	@SuppressWarnings("resource")
	private InputStream getInputStream(HttpServletResponse response) throws FileNotFoundException {
		InputStream is;
		String fName = null;
		if (filePath != null && !filePath.isEmpty()) {
			File file = new File(filePath);
			fName = file.getName();
			if (contentType == null) {
				String mimeType = mimetypesFileTypeMap.getContentType(file);
				contentType = mimeType != null ? mimeType : APPLICATION_OCTET_STREAM;
			}
			response.setContentLength((int) file.length());
			is = new FileInputStream(file);
		} else {
			is = inputStream;
		}
		if (attached && (fileNameDisplayed != null || fName != null)) {
			response.addHeader(CONTENT_DISPOSITION, ATTACHMENT_FILENAME + (fileNameDisplayed != null ? fileNameDisplayed : fName));
		}
		return is;
	}

	public void render(Map<String, ?> paramMap, HttpServletRequest request, HttpServletResponse response) throws Exception {
		try {
			response.addHeader(CACHE_CONTROL, NO_CACHE);
			OutputStream out = response.getOutputStream();
			byte[] bbuf = new byte[128];
			int length = 0;
			DataInputStream in = new DataInputStream(getInputStream(response));
			while (in != null && (length = in.read(bbuf)) != -1) {
				out.write(bbuf, 0, length);
			}
			in.close();
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}
